#pragma once
#include <zGraphicsConfig.hpp>
#include "../Graphics/OpenGLTools.hpp"
#include "../GraphicsGUI/CameraGUI.hpp"
#include "../Context/Context.hpp"
#include "../Graphics/Color.hpp"
#include "../Resource/ResourceManager.hpp"

namespace zzz
{
class Context;
class ZGRAPHICS_CLASS Renderer : public Uncopyable
{
public:
  Renderer();
  virtual ~Renderer();
  // Called by context, before OpenGL is inited.
  virtual void SetContext(Context *context);
  Context* GetContext(){return context_;}
  // Will set context dirty.
  void Redraw();
  // Redraw instantly, do not call this in draw! A recurrsive draw will happen!
  void InstantRedraw();
  // Make attached context current.
  void MakeCurrent();
  // Top level draw function, called by context.
  // Should clear background, and call Draw() then call RenderText();
  virtual bool RenderScene();
  // Called after OpenGL inited, be overriden to generate data.
  virtual bool InitData();
  // Called after OpenGL inited, be overriden to set OpenGL status.
  virtual bool InitState();

  int width_,height_;
  CameraGUI camera_;

  GraphicsGUI<Renderer> *gui_;
protected:
  // It is called by RenderScene()
  // Need to set camera etc. and call DrawObj().
  // Usually only need to override SetupCamera() and DrawObj().
  virtual bool Draw();

  // It will be called every frame, to ganerate msg inside msg_.
  virtual void CreateMsg();

  // Setup ModelView matrix. Matrix mode will be set to ModelView before it is called.
  // Just do the work but do not PushMatrix or set MatrixMode
  virtual void SetupCamera();

  // Called by Draw(), do the real drawing.
  virtual void DrawObj();
  
  // Will be called by RenderScene(), to render msg_ to screen.
  virtual void RenderText(const string &t);

  // Will be called by OnSize, should setup those objects who need windows size
  virtual void AfterOnSize(unsigned int nType, int cx, int cy);
protected:
  bool showMsg_;
  string msg_;
  double SPF_,FPS_;
  Context *context_;

public:
  //for mouse position
  //all context should convert into that;
  //topleft is 0,0
  //x increases along left to right
  //y increases along top to bottom
  virtual void OnMouseMove(unsigned int nFlags,int x,int y);
  virtual void OnLButtonDown(unsigned int nFlags,int x,int y);
  virtual void OnLButtonUp(unsigned int nFlags,int x,int y);
  virtual void OnRButtonDown(unsigned int nFlags,int x,int y);
  virtual void OnRButtonUp(unsigned int nFlags,int x,int y);
  virtual void OnMButtonDown(unsigned int nFlags,int x,int y);
  virtual void OnMButtonUp(unsigned int nFlags,int x,int y);
  virtual void OnMouseWheel(unsigned int nFlags, int zDelta, int x,int y);
  virtual void OnSize(unsigned int nType, int cx, int cy);
  virtual void OnChar(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags);
  virtual void OnKeyDown(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags);
  virtual void OnKeyUp(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags);
  virtual void OnIdle();

public:
  //ATTENTION this cannot be inside glBegin~glEnd
  Vector3d UnProject(double winx,double winy,double winz=0) const;
  void SetRasterPos(double winx,double winy) const;
};
}